package aquerius

/**
 * @author: Yardena
 * @date: Aug 1, 2009 5:23:00 PM
 */

trait ObjectDatabase extends Database {

  type TableType = ScalaObject
  type ResultType[X] = Iterable[X]

  type ExpressionType[-X,+Y]   = this.Expression[X,Y]
  type BoolExpressionType[-X] = this.BoolExpression[X]
  type IntExpressionType[-X]  = this.IntExpression[X]
  type StrExpressionType[-X]  = this.StrExpression[X]

  class Expression[-F,+T](val function: (F => T)) extends super.Expression[F,T] {
    def is[S<:F]    (other: Expression[S,_]) = new BoolExpression (t => this.function(t) == other.function(t))
    def isNot[S<:F] (other: Expression[S,_]) = new BoolExpression (t => this.function(t) != other.function(t))
  }

  class BoolExpression[-F](function: (F => Boolean)) extends Expression[F,Boolean](function) with super.BoolExpression[F] {
    override def and[S<:F] (other: BoolExpression[S]) = new BoolExpression[S] (t => this.function(t) && other.function(t))
    override def or[S<:F]  (other: BoolExpression[S]) = new BoolExpression[S] (t => this.function(t) || other.function(t))
    override def not: BoolExpression[_ >: F]  = new BoolExpression[F] (!this.function(_))
  }

  class IntExpression[-F](function: (F => Int)) extends Expression[F,Int](function) with super.IntExpression[F] {
    override def +[S<:F] (other: IntExpression[S]) = new IntExpression[S](t => this.function(t) + other.function(t))
    override def -[S<:F] (other: IntExpression[S]) = new IntExpression[S](t => this.function(t) - other.function(t))
    override def >[S<:F] (other: IntExpression[S]) = new BoolExpression[S](t => this.function(t) > other.function(t))
    override def <[S<:F] (other: IntExpression[S]) = new BoolExpression[S](t => this.function(t) < other.function(t))
  }

  class StrExpression[-F](function: (F => String)) extends Expression[F,String](function) with super.StrExpression[F] {
    override def startsWith[S<:F] (str : StrExpression[S]) = new BoolExpression[S](t => this.function(t) startsWith str.function(t))
    override def contains[S<:F]   (str : StrExpression[S]) = new BoolExpression[S](t => (this.function(t) indexOf str.function(t)) >= 0)
  }

  implicit def const(b: Boolean) = new BoolExpression[Any] (_ => b)
  implicit def const(i: Int)     = new IntExpression[Any]  (_ => i)
  implicit def const(s: String)  = new StrExpression[Any] (_ => s)

  trait ScalaObject extends Table { self =>
    type ColumnType[+X]  = Property[X]
    type BoolColumnType = BoolProperty
    type IntColumnType  = IntProperty
    type StrColumnType  = StrProperty

    def eval(in: InputType): Iterable[RecordType]

    trait Property[+T] extends Expression[RecordType,T] with Column[T] {
      def apply(r: RecordType)   = function(r)
//      def eval(in: InputType)    = self.eval(in).map(function)
    }
    class BoolProperty(f: (RecordType => Boolean)) extends BoolExpression[RecordType](f) with Property[Boolean]
    class IntProperty (f: (RecordType => Int))     extends IntExpression[RecordType](f)  with Property[Int]
    class StrProperty (f: (RecordType => String))  extends StrExpression[RecordType](f)  with Property[String]

    def bool(f: RecordType => Boolean)  = new BoolProperty(f)
    def int (f: RecordType => Int)      = new IntProperty(f)
    def str (f: RecordType => String)   = new StrProperty(f)

    type QueryType = ObjectQuery
    class ObjectQuery(val condition: BoolExpressionType[RecordType]) extends Query {
      def apply(in: InputType) = self.eval(in).filter(condition.function)
    }
    def query(condition: BoolExpressionType[RecordType]) = new ObjectQuery(condition)
  }

}